package no.netlight.gotogate;

import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import no.netlight.gotogate.*;


public class Neo4jServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
    throws IOException, ServletException
    {
    	String loc = request.getParameter("location");
    	String flyplass = "OSL";
    	int flightDate = Integer.parseInt(request.getParameter("fDate"));
    	String flightNo = request.getParameter("flightNo");
    	String checkedIn = request.getParameter("checkedIn");
    	String luggage = request.getParameter("luggage");
    	SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
    	Calendar calendar = Calendar.getInstance();
    	calendar.add(Calendar.DAY_OF_YEAR,flightDate);
    	Date travelDate = calendar.getTime();
    	String travelDayOfWeek = Integer.toString(calendar.get(Calendar.DAY_OF_WEEK));
    	AvinorParser avinor;
    	try {
			avinor = new AvinorParser(flightNo,flyplass,"D",format.format(travelDate),Integer.toString((flightDate+1)*24));
		} catch (Exception e) {
			e.printStackTrace();
			avinor = null;
			return;
		}
    	Flight flight = avinor.getSearchedFlight();
    	Route[] routes = null;
    	String errorMsg = "";
    	Airport airport;
    	Airport destAirport=null;
    	String[] depTimes=null;
    	Date fDate = null;
    	boolean rushCheckIn = false, rushBagDrop=false,rushSecurity=false,rushGate=false;
    	
    	if(flight != null){
	    	String depTime = flight.getScheduleTime();
	    	depTimes = depTime.split(":");
	    	format = new SimpleDateFormat("Z");
	    	int summerTimeCorrection = Integer.parseInt(depTimes[0])+Integer.parseInt(format.format(travelDate).substring(1,3));
	    	if(summerTimeCorrection>23){
	    		summerTimeCorrection -= 24;
	    		flightDate += 1;
	    	} 
	    	depTimes[0] = Integer.toString(summerTimeCorrection);
	    	//add at-the-airport information
	    	String current = "";
	    	String startTime = "";
	    	String endTime = "";
	    	Route route = new Route();
	    	//should be at gate 30 min before departure time
	    	endTime = addTime(depTimes[0]+depTimes[1],-30);
	    	airport = flight.getDepartureAirport();
	    	destAirport = flight.getDestinationAirport();
	    	
	    	rushGate = airport.isHeavyTraffic(endTime, travelDayOfWeek);
	    	startTime = addTime(endTime,-1*Integer.parseInt(airport.getTimeWalkingToGate(endTime, travelDayOfWeek, flight.getDomesticOrInternational())));
	    	current = "Gate";
	    	String previous = "Security";
	    	if(flight.getGate()!=null){
	    		current += " "+flight.getGate();
	    	}
	    	route.addSegment(previous,current,"at_airport_info",startTime,endTime);
	    	current = previous;
	    	endTime = startTime;
	    	rushSecurity = airport.isHeavyTraffic(endTime, travelDayOfWeek);
	    	startTime = addTime(endTime,-1*Integer.parseInt(airport.getTimeSecurityCheck(endTime, travelDayOfWeek)));
	    	if(luggage.equals("true")){
	    		previous = "Bag drop";
	    		route.addSegment(previous,current,"at_airport_info",startTime,endTime);
	    		current = previous;
	    		endTime = startTime;
	    		rushBagDrop = airport.isHeavyTraffic(endTime, travelDayOfWeek);
		    	startTime = addTime(endTime,-1*Integer.parseInt(airport.getTimeBagDrop(endTime, travelDayOfWeek)));
	    	}
	    	if(checkedIn.equals("false")){
	    		previous = "Check-in";
	    		if(flight.getCheckInDesk()!=null){
	    			previous += " at desk "+flight.getCheckInDesk();
	    		}
	    		route.addSegment(previous,current,"at_airport_info",startTime,endTime);
	    		current = previous;
	    		endTime = startTime;
	    		rushCheckIn = airport.isHeavyTraffic(endTime, travelDayOfWeek);
		    	startTime = addTime(endTime,-1*Integer.parseInt(airport.getTimeCheckIn(endTime, travelDayOfWeek)));
	    	}
	    	route.addSegment("Oslo Lufthavn",current,"at_airport_info",startTime,endTime);
	    	
	    	
	    	String suffix = "001";
	    	GraphConstructor gdb = new GraphConstructor(flyplass+suffix);
	    	if(gdb.DatabaseIsEmpty("Oslo Lufthavn")){
				SpreadsheetHandler sh = new SpreadsheetHandler();
				//gdb.generateGraphFromRouteTable(sh.fetchInfo("http://spreadsheets.google.com/feeds/list/to0r8D9lbHK8hvcaewY_n1g/od6/public/values"));
				gdb.generateGraphFromRouteTable(sh.fetchInfo("http://spreadsheets.google.com/feeds/list/tmKB2PfTvpRkn8-9_iTA93Q/od6/public/values"));
			}
			RouteGenerator gdh = new RouteGenerator(gdb);
			routes = gdh.getAllRoutes(loc, "Oslo Lufthavn", startTime, 10);
			gdb.shutdown();
			if(routes!=null){
				for(Route r : routes){
					ArrayList<HashMap<String,String>>segments = route.getSegments();
					for(int i=0;i<segments.size();i++){
						HashMap<String,String> seg = segments.get(i);
						r.addSegment(seg, r.getSegments().size());
					}
				}
			} else {
				routes = new Route[1];
				routes[0] = route;
				errorMsg = "no routes";
			}
    	} else {
    		errorMsg = "no flight";
    	}
    	
		//generate response
        response.setContentType("text/xml");
        response.setHeader("Cache-Control", "no-cache");
        ArrayList<HashMap<String,String>> allSegs;
    	HashMap<String,String> seg;
        PrintWriter out = response.getWriter();
        out.println("{");
        if(routes!=null){
	        out.println("\"routes\": [ ");
	        Route r;
	        for(int i=0;i<routes.length;i++){
	        	if(i>4){
	        		break;
	        	}
	        	r = routes[i];
	        	out.println("{\"transfers\": \""+r.getTransfers()+"\", ");
	        	out.println("\"time\": \""+r.getTotalTime()+"\", ");
	        	out.println("\"segments\": [ ");
	        	allSegs = r.getSegments();
	        	for(int j=0;j<allSegs.size();j++){
	        		seg = allSegs.get(j);
	        		out.println("{\"from\": \""+seg.get("from")+"\", ");
	        		out.println("\"to\": \""+seg.get("to")+"\", ");
	        		out.println("\"type\": \""+seg.get("type")+"\", ");
	        		out.println("\"dep\": \""+seg.get("dep")+"\", ");
	        		out.println("\"arr\": \""+seg.get("arr")+"\"}");
	        		if(j!=(allSegs.size()-1)){
	        			out.println(",");
	        		}
	        	}
	        	out.println("]}");
	        	if(i!=(routes.length-1)){
	    			out.println(",");
	    		}
	        }
	        out.println("],");
        }
        if(errorMsg.equals("no routes")){
        	out.println("\"error\": \""+errorMsg+"\",");
        }
        if (!errorMsg.equals("no flight")){
        	format = new SimpleDateFormat("EEE,yyyy-MM-dd");
        	out.println("\"flight\": { \"destCode\": \""+destAirport.getCode()+"\", ");
        	out.println("\"depTime\": \""+depTimes[0]+depTimes[1]+"\", ");
        	out.println("\"depDate\": \""+format.format(travelDate)+"\", ");
        	out.println("\"rushCheckIn\": \""+rushCheckIn+"\", ");
        	out.println("\"rushBagDrop\": \""+rushBagDrop+"\", ");
        	out.println("\"rushSecurity\": \""+rushSecurity+"\", ");
        	out.println("\"rushGate\": \""+rushGate+"\", "); 
        	out.println("\"flightNo\": \""+flight.getFlightId()+"\", ");
        	out.println("\"gateClosed\": \""+addTime(depTimes[0]+depTimes[1],-20)+"\", ");
        	out.println("\"domesticOrInternational\": \""+flight.getDomesticOrInternational()+"\"}");
        } else {
        	out.println("\"error\": \""+errorMsg+"\"");
        }
        	
        out.println("}");
        
    }
    private String addTime(String time, int value) {
		int hrs = Integer.parseInt((time.substring(0, 2)));
		int min = Integer.parseInt((time.substring(2)));
		min += value;
		String resultString = "";
		if (min > 60) {
			hrs++;
			min -= 60;
		}
		if (min < 0) {
			hrs--;
			min += 60;
		}
		if (hrs < 10) {
			resultString += "0";
		}
		resultString += Integer.toString(hrs);
		if (min < 10) {
			resultString += "0";
		}
		resultString += Integer.toString(min);
		return resultString;
	}
}